﻿using MvvmCross.Core.ViewModels;
using Sidvall.Serialization;
using Sidvall.UI.Navigation;
using Sidvall.UI.Views;
using System.Threading.Tasks;

namespace Sidvall.UI.Presenters
{
    public abstract class RegionPresenterBase : IViewFactory
    {
        #region Public Members

        #region LogManager

        private Sidvall.Logging.LogManager _LogManager;
        public Sidvall.Logging.LogManager LogManager
        {
            get
            {
                if (_LogManager != null)
                    return _LogManager;
                return Sidvall.SystemContext.Current.LogManager;
            }
            set
            {
                _LogManager = value;
            }
        }

        #endregion

        public abstract object MainWindow { get; }
        public abstract void CloseApplication();
        public abstract object CreateView(MvxViewModelRequest request);

        #region AddPresentationHintHandler

        public virtual void AddPresentationHintHandler<THint>(System.Func<THint, bool> action) where THint : MvxPresentationHint
        {
        }

        #endregion
        #region ChangePresentation

        public async void ChangePresentation(MvxPresentationHint hint)
        {
            var mvxClosePresentationHint = hint as MvxClosePresentationHint;
            if (mvxClosePresentationHint != null)
            {
                Sidvall.UI.SystemContext.Current.NavigationManager.GoBack();
                return;
            }

            var presentationHint = hint as Sidvall.UI.ViewModels.PresentationHint;
            if (presentationHint != null)
            {
                switch (presentationHint.ActionType)
                {
                    case ViewModels.ViewModelActionType.CloseApplication:
                        CloseApplication();
                        break;
                    case ViewModels.ViewModelActionType.CloseView:
                        await Sidvall.UI.SystemContext.Current.ConfigurationContext.Regions.RemoveViewAsync(this.MainWindow, presentationHint.Context);
                        break;
                    case ViewModels.ViewModelActionType.GoBack:
                        Sidvall.UI.SystemContext.Current.NavigationManager.GoBack();
                        break;
                    case ViewModels.ViewModelActionType.GoForward:
                        Sidvall.UI.SystemContext.Current.NavigationManager.GoForward();
                        break;
                    case ViewModels.ViewModelActionType.GoToPosition:
                        Sidvall.UI.SystemContext.Current.NavigationManager.GoToPosition(presentationHint.Context.ToInt32(-1));
                        break;
                    case ViewModels.ViewModelActionType.Refresh:
                        Sidvall.UI.SystemContext.Current.NavigationManager.Refresh();
                        break;
                    case ViewModels.ViewModelActionType.GoToPreviousRequest:
                        Sidvall.UI.ViewModels.PresentationManager.ShowViewModel(this.LastRequest);
                        break;
                    default:
                        break;
                }
                return;
            }
        }

        #endregion
        #region Show

        public async void Show(MvxViewModelRequest request)
        {
            Region region;

            if (request == null)
                throw new System.ArgumentNullException(nameof(request));

            // Get region name
            var regionName = Region.GetRegionName(request.PresentationValues);
            this.LastRequest = request;

            // Show view
            try
            {
                region = await Sidvall.UI.SystemContext.Current.ConfigurationContext.Regions.ShowViewAsync(this.MainWindow, regionName, this, request);
            }
            catch (System.Exception ex)
            {
                await LogAsync(ex);
                await Sidvall.UI.SystemContext.Current.DialogManager.ShowDialogErrorMessageAsync(ex);
                region = null;
            }

            // Add view to navigation history
            if (region != null)
            {
                if (Sidvall.UI.Navigation.NavigationManager.AddToHistory(request.PresentationValues))
                {
                    var state = new HistoryRegionItem()
                    {
                        Request = request,
                        RegionName = region.Name
                    };
                    Sidvall.UI.SystemContext.Current.NavigationManager.AddHistoryItem(state);
                }
            }
        }

        #endregion

        #endregion
        #region Private Members

        private MvxViewModelRequest LastRequest { get; set; }

        #region LogAsync

        private async Task LogAsync(System.Exception ex)
        {
            if (this.LogManager != null)
                await this.LogManager.WriteAsync(ex, Sidvall.Logging.LogCategories.Application);
        }

        #endregion

        #endregion
        #region Constructors

        protected RegionPresenterBase()
        {
        }

        #endregion
    }
}
